#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msticker.h>
#include <mutex>
#include <ohaudio/native_audio_routing_manager.h>
#include <ohaudio/native_audiocapturer.h>
#include <ohaudio/native_audiostream_base.h>
#include <ohaudio/native_audiostreambuilder.h>
#include <queue>
#include <fstream>

struct AudioDeviceInfo {
	uint32_t id;
	std::string name;
	std::string address;
	MSSndCardDeviceType autoType;
	uint32_t inputCount = 0;
	uint32_t outputCount = 0;
	uint32_t supportedClockRates{0};
	uint32_t supportedChannelCounts{0};
};

struct AudioContext {
	AudioContext() {
		nchannels = 1;
		builtin_aec = false;
		device_changed = false;
	}
	int nchannels;
	bool builtin_aec;
	bool device_changed;
};


std::string AudioDeviceTypeToString(OH_AudioDevice_Type type) {
	switch (type) {
		case AUDIO_DEVICE_TYPE_INVALID:
			return "Invalid";
		case AUDIO_DEVICE_TYPE_EARPIECE:
			return "Earpiece";
		case AUDIO_DEVICE_TYPE_SPEAKER:
			return "Speaker";
		case AUDIO_DEVICE_TYPE_WIRED_HEADSET:
			return "Headset";
		case AUDIO_DEVICE_TYPE_WIRED_HEADPHONES:
			return "Wired headphones";
		case AUDIO_DEVICE_TYPE_BLUETOOTH_SCO:
			return "Bluetooth SCO";
		case AUDIO_DEVICE_TYPE_BLUETOOTH_A2DP:
			return "Bluetooth A2DP";
		case AUDIO_DEVICE_TYPE_MIC:
			return "Microphone";
		case AUDIO_DEVICE_TYPE_USB_HEADSET:
			return "USB headset";
		case AUDIO_DEVICE_TYPE_DISPLAY_PORT:
			return "Display port";
		case AUDIO_DEVICE_TYPE_REMOTE_CAST:
			return "Remote cast";
		case AUDIO_DEVICE_TYPE_DEFAULT:
			return "Default";
		default:
			break;
	}
	return "Unspecified";
}

MSSndCardDeviceType GetAudioDeviceType(OH_AudioDevice_Type type) {
	switch (type) {
		case AUDIO_DEVICE_TYPE_INVALID:
			return  MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_UNKNOWN;
		case AUDIO_DEVICE_TYPE_EARPIECE:
			return  MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_EARPIECE;
		case AUDIO_DEVICE_TYPE_SPEAKER:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_SPEAKER;
		case AUDIO_DEVICE_TYPE_WIRED_HEADSET:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADSET;
		case AUDIO_DEVICE_TYPE_WIRED_HEADPHONES:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADPHONES;
		case AUDIO_DEVICE_TYPE_BLUETOOTH_SCO:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH;
		case AUDIO_DEVICE_TYPE_BLUETOOTH_A2DP:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH_A2DP;
		case AUDIO_DEVICE_TYPE_MIC:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_MICROPHONE;
		case AUDIO_DEVICE_TYPE_USB_HEADSET:
			return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADSET;
		default:
			break;
	}
	return MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_UNKNOWN;
}


class AudioDeviceManager {
public:
	static std::vector<AudioDeviceInfo> GetDevices() {
		std::vector<AudioDeviceInfo> result;
		OH_AudioRoutingManager *audioRoutingManager = nullptr;
		OH_AudioCommon_Result ret = OH_AudioManager_GetAudioRoutingManager(&audioRoutingManager);
		if (ret != AUDIOCOMMON_RESULT_SUCCESS) {
			ms_message("Failed to get OH_AudioRoutingManager from ohos");
			return result;
		}
		OH_AudioDeviceDescriptorArray *audioDeviceDescriptorArray = nullptr;
		ret =
		    OH_AudioRoutingManager_GetDevices(audioRoutingManager, AUDIO_DEVICE_FLAG_ALL, &audioDeviceDescriptorArray);
		if (ret != AUDIOCOMMON_RESULT_SUCCESS) {
			ms_message("Failed to get audio Devices from ohos");
			return result;
		}
		for (uint32_t index = 0; index < audioDeviceDescriptorArray->size; index++) {
			AudioDeviceInfo device;

			OH_AudioDeviceDescriptor *descriptor = audioDeviceDescriptorArray->descriptors[index];
			uint32_t deviceId = 0;
			ret = OH_AudioDeviceDescriptor_GetDeviceId(descriptor, &deviceId);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				ms_message("get audio device id success");
				device.id = deviceId;
			}
			ms_message("%s: %d deviceId: %u", __FILE__, __LINE__, deviceId);
			char* address = nullptr;
			ret = OH_AudioDeviceDescriptor_GetDeviceAddress(descriptor, &address);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				ms_message("audio device mac address success");
				device.address = address;
			}
			char *name = nullptr;
			ret = OH_AudioDeviceDescriptor_GetDeviceName(descriptor, &name);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				ms_message("get audio device name success");
				device.name = name;
			}
			ms_message("%s: %d name: %s", __FILE__, __LINE__, name);
			uint32_t size;
			uint32_t *rates;
			ret = OH_AudioDeviceDescriptor_GetDeviceSampleRates(descriptor, &rates, &size);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				device.supportedClockRates = rates[0];
				ms_message("get audio rates success,rates:%d", rates[0]);
			}
		
			uint32_t *supportedChannelCounts;
			ret = OH_AudioDeviceDescriptor_GetDeviceChannelCounts(descriptor, &supportedChannelCounts, &size);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				ms_message("get audio channel Count success");
				device.supportedChannelCounts = supportedChannelCounts[0];
			}

			OH_AudioDevice_Role role = AUDIO_DEVICE_ROLE_INPUT;
			ret = OH_AudioDeviceDescriptor_GetDeviceRole(descriptor, &role);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				ms_message("get audio role success");
				if (role == AUDIO_DEVICE_ROLE_INPUT) {
					device.inputCount++;
				} else if (role == AUDIO_DEVICE_ROLE_OUTPUT) {
					device.outputCount++;
				}
			}
			ms_message("%s: %d role: %d", __FILE__, __LINE__, role);

			OH_AudioDevice_Type type = AUDIO_DEVICE_TYPE_INVALID;
			ret = OH_AudioDeviceDescriptor_GetDeviceType(descriptor, &type);
			if (ret == AUDIOCOMMON_RESULT_SUCCESS) {
				device.autoType = GetAudioDeviceType(type);
				ms_message("get audio type success");
			}
			ms_message("%s: %d type: %d", __FILE__, __LINE__, type);
			if (device.name.length() == 0) {
				device.name = AudioDeviceTypeToString(type) + " (" + std::to_string(device.id) + ")";
			}
			result.push_back(device);
		}

		OH_AudioRoutingManager_ReleaseDevices(audioRoutingManager, audioDeviceDescriptorArray);
		return result;
	}
};

class AudioRenderer;

struct OHOSAudioWriteData {
	OHOSAudioWriteData() {
		stype = 0;
		rate = 16000;
		nchannels = 1;
		nFramesRequested = 0;
		ms_mutex_init(&mutex, NULL);
		ms_bufferizer_init(&bf);
	}
	~OHOSAudioWriteData() {
		ms_mutex_destroy(&mutex);
		ms_bufferizer_uninit(&bf);
	}

	void setContext(AudioContext *context) {
		audio_context = context;
	}

	void updateStreamTypeFromMsSndCard() {
		MSSndCardStreamType type = ms_snd_card_get_stream_type(soundCard);
		stype = 0;
		if (type == MS_SND_CARD_STREAM_RING) {
			ms_message("Sound card configured for RING stream");
			stype = 2;
		} else if (type == MS_SND_CARD_STREAM_MEDIA) {
			ms_message("Sound card configured for MEDIA stream");
			stype = 3;
		} else if (type == MS_SND_CARD_STREAM_DTMF) {
			ms_message("Sound card configured for DTMF stream");
			stype = 8;
		} else {
			ms_message("Sound card configured for VOICE stream");
		}
	}
	MSSndCard *soundCard;
	int stype;
	MSBufferizer bf;
	AudioRenderer *tr;
	AudioContext *audio_context;
	int rate;
	int nchannels;
	int nbufs;
	int nFramesRequested;
	bool mStarted;
	uint64_t flowControlStart;
	int minBufferFilling;
	ms_mutex_t mutex;
};

class Buffer {
public:
	size_t frameCount; // number of sample frames corresponding to size;
	                   // on input it is the number of frames desired,
	                   // on output is the number of frames actually filled

	size_t size; // input/output in byte units
	union {
		void *raw;
		short *i16; // signed 16-bit
		int8_t *i8; // unsigned 8-bit, offset by 0x80
	};
};

class AudioRenderer {
private:
	uint32_t sampleRate;
	uint32_t channelCount;
	uint32_t frameSize;
	std::mutex mtx_;
	OHOSAudioWriteData *ad_{nullptr};
	std::queue<std::string> buffers_;
	OH_AudioRenderer *renderer_{nullptr};
	OH_AudioStreamBuilder *builder{nullptr};

public:
	AudioRenderer(uint32_t rate, uint32_t channel_count, uint32_t frame_size, OHOSAudioWriteData *writeData )
	    : sampleRate(rate), channelCount(channel_count), frameSize(frame_size), ad_(writeData) {
		initAudioRenderer();
	}
	static OH_AudioData_Callback_Result OnWriteData_1(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length) {
		auto self = (AudioRenderer *)userData;
		return self->OnWriteData(renderer, buffer, length);
	}

	static int32_t OnStreamEvent_1(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event) {
		auto self = (AudioRenderer *)userData;
		return self->OnStreamEvent(renderer, event);
	}

	static int32_t OnInterruptEvent_1(OH_AudioRenderer *renderer,
	                                  void *userData,
	                                  OH_AudioInterrupt_ForceType type,
	                                  OH_AudioInterrupt_Hint hint) {
		auto self = (AudioRenderer *)userData;
		return self->OnInterruptEvent(renderer, type, hint);
	}

	static int32_t OnError_1(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error) {
		auto self = (AudioRenderer *)userData;
		return self->OnError(renderer, error);
	}

	void SetBuffer(MSFilter *obj) {
		std::unique_lock<std::mutex> lock(mtx_);
		mblk_t *m;
		while ((m = ms_queue_get(obj->inputs[0])) != NULL) {
			mblk_t *o;
			msgpullup(m, -1);
			o = allocb((m->b_wptr - m->b_rptr) * 2, 0);
			mblk_meta_copy(m, o);
			buffers_.emplace(std::string((char *)m->b_rptr, (size_t)(m->b_wptr - m->b_rptr)));
			freemsg(m);
		}
	}

	void readBuffer(const void *p_info, Buffer *buffer) {
		*buffer = *(const Buffer *)p_info;
	}

	void writeBuffer(void *p_info, const Buffer *buffer) {
		*(Buffer *)p_info = *buffer;
	}

	OH_AudioData_Callback_Result OnWriteData(OH_AudioRenderer *renderer, void *buffer, int32_t length) {
		(void)renderer;
		int64_t position;
		int64_t timestamp;

		auto result = OH_AudioRenderer_GetTimestamp(renderer_, CLOCK_MONOTONIC, &position, &timestamp);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Ohos stream GetTimestamp fail");
			return AUDIO_DATA_CALLBACK_RESULT_INVALID;
		}
		if (!ad_ || length <= 0) {
			ms_message("AudioRenderer OnWriteData ad_ is null ");
			return AUDIO_DATA_CALLBACK_RESULT_INVALID;
		}
	ms_mutex_lock(&ad_->mutex);
    
    int bufSize = ms_bufferizer_get_avail(&ad_->bf);
    
    // 改进的缓冲区管理：如果数据不足，等待一小段时间看是否有新数据到达
    if (bufSize < length && ad_->mStarted) {
 
        int missingBytes = length - bufSize;
        int waitTime = (missingBytes * 1000) / (ad_->nchannels * 2 * ad_->rate); // 毫秒
        
        ms_mutex_unlock(&ad_->mutex);
        ms_usleep(MIN(waitTime, 5) * 1000); // 最多等待5ms
        ms_mutex_lock(&ad_->mutex);
        
        // 重新检查缓冲区
        bufSize = ms_bufferizer_get_avail(&ad_->bf);
    }
    
    // 从缓冲区读取数据
    int readBytes = MIN(bufSize, length);
    if (readBytes > 0) {
        ms_bufferizer_read(&ad_->bf, (uint8_t *)buffer, readBytes);
    }
    
    // 如果数据仍然不足，尽量减少静音填充
    if (readBytes < length) {
        int silentBytes = length - readBytes;
        ms_warning("Buffer underrun: requested %d bytes, but only %d available, padding %d bytes with silence", 
                  length, readBytes, silentBytes);
        memset((uint8_t *)buffer + readBytes, 0, silentBytes);
        
        // 更新最小缓冲区填充量（用于流量控制）
        if (ad_->minBufferFilling == -1 || bufSize < ad_->minBufferFilling) {
            ad_->minBufferFilling = bufSize;
        }
    }
    
    ms_mutex_unlock(&ad_->mutex);
    return AUDIO_DATA_CALLBACK_RESULT_VALID;
	}

	int32_t OnStreamEvent(OH_AudioRenderer *renderer, OH_AudioStream_Event event) {
		(void)renderer;
		return 0;
	}

	int32_t OnInterruptEvent(OH_AudioRenderer *renderer, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint) {
		(void)renderer;
		(void)hint;

		return 0;
	}

	int32_t OnError(OH_AudioRenderer *renderer, OH_AudioStream_Result error) {
		(void)renderer;
		ms_message("AudioRenderer Ohos stream callback error:%d", error);
		return 0;
	}

	int start() {
		OH_AudioStream_Result ret = OH_AudioStream_Result::AUDIOSTREAM_ERROR_SYSTEM;
		if (renderer_) {
			ret = OH_AudioRenderer_Start(renderer_);
		} else {
			initAudioRenderer();
			ret = OH_AudioRenderer_Start(renderer_);
		}
		return ret;
	}

	void stop() {
		OH_AudioRenderer_Stop(renderer_);
	}

	void destroy() {
		if (renderer_) {
			OH_AudioRenderer_Release(renderer_);
			renderer_ = nullptr;
		}
		if (builder) {
			OH_AudioStreamBuilder_Destroy(builder);
			builder = nullptr;
		}
	}

private:
	void initAudioRenderer() {
		ms_message("initAudioRenderer start");
		OH_AudioStreamBuilder *builder = nullptr;
		auto result = OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_RENDERER);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream Builder fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetSamplingRate(builder, sampleRate);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream SetSamplingRate fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetChannelCount(builder, channelCount);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream SetChannelCount fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream SetLatencyMode fail");
			return;
		}
		OH_AudioStreamBuilder_SetRendererInfo(builder,AUDIOSTREAM_USAGE_VIDEO_COMMUNICATION);
		OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
		OH_AudioRenderer_Callbacks callbacks;
		callbacks.OH_AudioRenderer_OnWriteData = nullptr;//OnWriteData_1
		callbacks.OH_AudioRenderer_OnStreamEvent = OnStreamEvent_1;
		callbacks.OH_AudioRenderer_OnInterruptEvent = OnInterruptEvent_1;
		callbacks.OH_AudioRenderer_OnError = OnError_1;
		result = OH_AudioStreamBuilder_SetRendererCallback(builder, callbacks, this);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream SetRendererCallback fail%d",frameSize);
			return;
		}
		OH_AudioStreamBuilder_SetRendererWriteDataCallback(builder, OnWriteData_1, this);
		OH_AudioRenderer *stream = nullptr;

		result = OH_AudioStreamBuilder_GenerateRenderer(builder, &stream);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioRenderer Creating Ohos stream GenerateRenderer fail");
			return;
		}
		renderer_ = stream;
		ms_message("initAudioRenderer success");
	}
};

/**ohos auido capture*/
class AudioCapturer {
public:
	uint32_t sampleRate;
	uint32_t channelCount;
	OH_AudioCapturer *audioCapturer{nullptr};
	OH_AudioStreamBuilder *builder{nullptr};
	std::mutex mtx_;
	std::string buffer_;
	int64_t timestamp_{0};
	MSTickerSynchronizer *mTickerSynchronizer {NULL};
	MSFilter *mFilter {NULL};
	uint64_t read_samples {0};
	queue_t q;

public:
	AudioCapturer(uint32_t rate, uint32_t count) : sampleRate(rate), channelCount(count) {
		qinit(&q);
		initAudioCapt();
	}
	~AudioCapturer() {
		destroy();
	}
	int start() {
		OH_AudioStream_Result ret = OH_AudioStream_Result::AUDIOSTREAM_ERROR_SYSTEM;
		if (audioCapturer) {
			ret = OH_AudioCapturer_Start(audioCapturer);
		} else {
			initAudioCapt();
			ret = OH_AudioCapturer_Start(audioCapturer);
		}

		return ret;
	}

	void stop() {
		if (audioCapturer) {
			OH_AudioCapturer_Stop(audioCapturer);
		}
	}

	void destroy() {
		ms_message("AudioCapturer destroy");
		if (audioCapturer) {
			OH_AudioCapturer_Release(audioCapturer);
			audioCapturer = nullptr;
		}
		if (builder) {
			OH_AudioStreamBuilder_Destroy(builder);
			builder = nullptr;
		}
	}

	static int32_t OnReadData_1(OH_AudioCapturer *stream, void *userData, void *buffer, int32_t length) {
		AudioCapturer *self = reinterpret_cast<AudioCapturer *>(userData);
		return self->OnReadData(stream, buffer, length, self->channelCount);
	}

	static int32_t Capt_OnError_1(OH_AudioCapturer *stream, void *userData, OH_AudioStream_Result error) {
		AudioCapturer *self = reinterpret_cast<AudioCapturer *>(userData);
		return self->OnError(stream, error);
	}

	int32_t OnError(OH_AudioCapturer *stream, OH_AudioStream_Result error) {
		(void)stream;
		ms_message("AudioCapturer Ohos stream callback error:%d", error);
		return 0;
	}

	// 函数用于将void *数组转换为int16_t数组
	void convertVoidToInt16(void *buffer, int bufferSize, int16_t **result, size_t *resultSize) {
		*resultSize = bufferSize / sizeof(int16_t);
		*result = (int16_t *)malloc(*resultSize * sizeof(int16_t));
		if (*result == NULL) {
			return;
		}
		// 使用memcpy进行内存复制
		memcpy(*result, buffer, bufferSize);
	}

	void GetBuffer(MSQueue *output) {
		std::unique_lock<std::mutex> lock(mtx_);
		mblk_t *om;
		while ((om = getq(&q)) != NULL) {
			ms_queue_put(output, om);
		}
	}

	int32_t OnReadData(OH_AudioCapturer *renderer, void *buffer, int32_t length, int32_t channelOut) {
		std::unique_lock<std::mutex> lock(mtx_);
		if (mTickerSynchronizer == NULL) {
			mTickerSynchronizer = ms_ticker_synchronizer_new();
			ms_ticker_set_synchronizer(mFilter->ticker, mTickerSynchronizer);
		}

		mblk_t *m = allocb(length, 0);
		if (m == nullptr) {
        	ms_error("Failed to allocate mblk_t");
        	return -1;
    	}
		memcpy(m->b_wptr, buffer, length);
		m->b_wptr += length;

    	const int bytesPerSample = 2; //SampleFormat为AUDIOSTREAM_SAMPLE_S16LE，音频位深为2
    	const int channels = channelOut;    
    	int samplesInThisFrame = length / (bytesPerSample * channels);
		read_samples += samplesInThisFrame;
		// read_samples += 1;
		ms_ticker_synchronizer_update(mTickerSynchronizer, read_samples, sampleRate);
		putq(&q, m);
		return 0;
	}

private:
	void initAudioCapt() {
		ms_message("initAudioCapt start,audioCapturer:%p", audioCapturer);
		if (audioCapturer) {
			destroy();
		}

		auto result = OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioCapturer Creating Ohos stream Builder fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetSamplingRate(builder, sampleRate);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioCapturer Creating Ohos stream SetSamplingRate fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetChannelCount(builder, channelCount);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioCapturer Creating Ohos stream SetChannelCount fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("AudioCapturer Creating Ohos stream SetLatencyMode fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("OH_AudioStreamBuilder_SetSampleFormat fail");
			return;
		}
		result = OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("OH_AudioStreamBuilder_SetEncodingType fail");
			return;
		}
		OH_AudioCapturer_Callbacks callbacks;
		memset(&callbacks, 0, sizeof(OH_AudioCapturer_Callbacks));
		callbacks.OH_AudioCapturer_OnReadData = OnReadData_1;
		callbacks.OH_AudioCapturer_OnError = Capt_OnError_1;
		callbacks.OH_AudioCapturer_OnInterruptEvent = nullptr;
		callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;
		result = OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, this);
		if (result != AUDIOSTREAM_SUCCESS) {
			ms_message("OH_AudioStreamBuilder_SetCapturerCallback fail");
			return;
		}
		OH_AudioCapturer *stream = nullptr;
		result = OH_AudioStreamBuilder_GenerateCapturer(builder, &stream);
		if (stream == nullptr) {
		}
		audioCapturer = stream;
		ms_message("initAudioCapt success");
	}
};

typedef struct _AlawEncData {
	MSBufferizer *bz;
	int ptime;
	int maxptime;
	uint32_t ts;
	MSSndCard *soundCard;
	AudioCapturer *rec_engine;
	uint64_t flowControlStart;
	AudioContext *audio_context;
	int sample_rate;
	int deviceId;
} AlawEncData;

static void alaw_enc_data_destroy(AlawEncData *obj) {
	ms_bufferizer_destroy(obj->bz);
	ms_free(obj);
}

static void alaw_enc_init(MSFilter *obj) {
	ms_message("alaw_enc_init");
	obj->data = (AlawEncData *)ms_new0(AlawEncData, 1);
}

static void ohos_snd_read_preprocess(MSFilter *filter)
{
	AlawEncData *obj = (AlawEncData *)filter->data;
	obj->bz = ms_bufferizer_new();
	obj->ptime = 0;
	obj->maxptime = MIN(MS_DEFAULT_MAX_PTIME, 140);
	obj->ts = 0;
	obj->rec_engine = new AudioCapturer(obj->sample_rate, obj->audio_context->nchannels);
	obj->rec_engine->start();
	obj->rec_engine->mFilter = filter;
}

static void alaw_enc_uninit(MSFilter *obj) {
	AlawEncData *dt = (AlawEncData *)obj->data;
	dt->rec_engine->stop();
	delete dt->rec_engine;

	alaw_enc_data_destroy((AlawEncData *)obj->data);
}

static void alaw_enc_process(MSFilter *obj) {
	AlawEncData *dt = (AlawEncData *)obj->data;
	dt->rec_engine->GetBuffer(obj->outputs[0]);
}

static int enc_add_attr(MSFilter *f, void *arg) {
	const char *fmtp = (const char *)arg;
	AlawEncData *s = (AlawEncData *)f->data;
	if (strstr(fmtp, "ptime:10") != NULL) {
		s->ptime = 10;
	} else if (strstr(fmtp, "ptime:20") != NULL) {
		s->ptime = 20;
	} else if (strstr(fmtp, "ptime:30") != NULL) {
		s->ptime = 30;
	} else if (strstr(fmtp, "ptime:40") != NULL) {
		s->ptime = 40;
	} else if (strstr(fmtp, "ptime:50") != NULL) {
		s->ptime = 50;
	} else if (strstr(fmtp, "ptime:60") != NULL) {
		s->ptime = 60;
	} else if (strstr(fmtp, "ptime:70") != NULL) {
		s->ptime = 70;
	} else if (strstr(fmtp, "ptime:80") != NULL) {
		s->ptime = 80;
	} else if (strstr(fmtp, "ptime:90") != NULL) {
		s->ptime = 90;
	} else if (strstr(fmtp, "ptime:100") != NULL) {
		s->ptime = 100;
	} else if (strstr(fmtp, "ptime:110") != NULL) {
		s->ptime = 110;
	} else if (strstr(fmtp, "ptime:120") != NULL) {
		s->ptime = 120;
	} else if (strstr(fmtp, "ptime:130") != NULL) {
		s->ptime = 130;
	} else if (strstr(fmtp, "ptime:140") != NULL) {
		s->ptime = 140;
	}
	return 0;
}

static int enc_add_fmtp(MSFilter *f, void *arg) {
	const char *fmtp = (const char *)arg;
	AlawEncData *s = (AlawEncData *)f->data;
	char tmp[30];
	if (fmtp_get_value(fmtp, "maxptime", tmp, sizeof(tmp))) {
		s->maxptime = MIN(atoi(tmp), MS_DEFAULT_MAX_PTIME);
	}
	if (fmtp_get_value(fmtp, "ptime", tmp, sizeof(tmp))) {
		ms_message("%s configured with ptime=%s", f->desc->name, tmp);
		s->ptime = MIN(atoi(tmp), s->maxptime);
		if (s->ptime == s->maxptime) ms_message("%s ptime set to maxptime=%i", f->desc->name, s->maxptime);
	}
	return 0;
}

static int get_channels(BCTBX_UNUSED(MSFilter *f), void *arg) {
	int *n = (int*)arg;
	AlawEncData *ictx = static_cast<AlawEncData*>(f->data);
	*n = ictx->audio_context->nchannels;
	return 0;
}

static int get_sample_rate(BCTBX_UNUSED(MSFilter *f), void *arg) {
	int *n = (int*)arg;
	AlawEncData *ictx = static_cast<AlawEncData*>(f->data);
	*n = ictx->sample_rate;
	return 0;
}

static int get_ptime(MSFilter *f, void *arg) {
	AlawEncData *s = (AlawEncData *)f->data;
	*((int *)arg) = s->ptime;
	return 0;
}

static MSFilterMethod enc_methods[] = {
    {MS_FILTER_ADD_ATTR, enc_add_attr},
	{MS_FILTER_ADD_FMTP, enc_add_fmtp},
    {MS_FILTER_GET_NCHANNELS, get_channels},
	{MS_FILTER_GET_SAMPLE_RATE, get_sample_rate},
    {MS_AUDIO_ENCODER_GET_PTIME, get_ptime},
	{0, NULL}
};

MSFilterDesc ms_ohos_audio_enc_desc = {.id = MS_OHOS_AUDIO_ENC,
                                       .name = "OHOSAudioEncode",
                                       .text = N_("ohos audio encoder"),
                                       .category = MS_FILTER_ENCODING_CAPTURER,
                                       .enc_fmt = "pcm",
                                       .ninputs = 0,
                                       .noutputs = 1,
                                       .init = alaw_enc_init,
									   .preprocess = ohos_snd_read_preprocess,
                                       .process = alaw_enc_process,
                                       .uninit = alaw_enc_uninit,
                                       .methods = enc_methods};

MS_FILTER_DESC_EXPORT(ms_ohos_audio_enc_desc)

extern "C" {
#include "g711.h"
}

// ================================================decoder========================================

static const int flowControlIntervalMs = 1000;
static const int flowControlThresholdMs = 40;

static void ohos_dec_init(MSFilter *obj) {
	ms_message("ohos_dec_init");
	OHOSAudioWriteData *ad = new OHOSAudioWriteData();
	obj->data = ad;
}

static void ohos_dec_uninit(MSFilter *obj) {
	OHOSAudioWriteData *ad = (OHOSAudioWriteData *)obj->data;
	delete ad;
}

static void ohos_dec_preprocess(MSFilter *obj) {
	OHOSAudioWriteData *ad = (OHOSAudioWriteData *)obj->data;
	ad->nFramesRequested = 0;
	ad->updateStreamTypeFromMsSndCard();
	ad->nbufs = 0;
	ad->mStarted = false;
	ad->flowControlStart = obj->ticker->time;
	ad->minBufferFilling = -1;
	uint32_t frameSize = ad->rate * 20 / 1000 * 16 / 8;
	ad->tr = new AudioRenderer(ad->rate, ad->nchannels, frameSize, ad);
}

static int bytes_to_ms(OHOSAudioWriteData *ad, int bytes) {
	return bytes * 1000 / (2 * ad->nchannels * ad->rate);
}

static void ohos_dec_process(MSFilter *obj) {
	OHOSAudioWriteData *ad = (OHOSAudioWriteData *)obj->data;
	if (!ad->tr) {
		ms_queue_flush(obj->inputs[0]);
		return;
	}
	if (!ad->mStarted) {
		ms_mutex_lock(&ad->mutex);
		if (!ad->mStarted) {
			ad->tr->start();
			ad->mStarted = true;
			ad->flowControlStart = obj->ticker->time;
            ad->minBufferFilling = 0;
		}
		ms_mutex_unlock(&ad->mutex);
	}
	ms_mutex_lock(&ad->mutex);
    ms_bufferizer_put_from_queue(&ad->bf, obj->inputs[0]);
    auto currentSize = ad->bf.size;
    
    if (ad->minBufferFilling == -1 || currentSize < ad->minBufferFilling) {
        ad->minBufferFilling = currentSize;
    }
  	uint32_t elapsedTime = obj->ticker->time - ad->flowControlStart;
    if (elapsedTime >= flowControlIntervalMs) {
        int threshold = (flowControlThresholdMs * ad->nchannels * 2 * ad->rate) / 1000;
        
        if (ad->minBufferFilling > threshold && ad->bf.size > threshold / 2) {
            int drop = ad->minBufferFilling - (threshold / 4);
            ms_warning(
                "Too many samples waiting in sound writer (minBufferFilling=%i ms, threshold=%i ms), dropping %i ms",
                bytes_to_ms(ad, ad->minBufferFilling), bytes_to_ms(ad, threshold), bytes_to_ms(ad, drop));
            if (drop > 0 && drop < ad->bf.size) {
                ms_bufferizer_skip_bytes(&ad->bf, drop);
            }
        }
        
        ad->flowControlStart = obj->ticker->time;
        ad->minBufferFilling = ad->bf.size;
    }
    
    ms_mutex_unlock(&ad->mutex);
}

static void ohos_dec_postprocess(MSFilter *obj) {
	OHOSAudioWriteData *ad = (OHOSAudioWriteData *)obj->data;
	if (!ad->tr) return;
	ms_message("Stopping sound playback");
	ad->tr->stop();
	ms_message("Sound playback flushed, deleting");
	ad->tr = NULL;
	ad->mStarted = false;
}

static int get_sample_write_rate(MSFilter *obj, void *data) {
	int *n = (int*)data;
	OHOSAudioWriteData *octx = static_cast<OHOSAudioWriteData*>(obj->data);
	*n = octx->rate;
	return 0;
}

static int set_sample_write_rate(MSFilter *obj, void *data) {
	int *rate = (int *)data;
	ms_message("%s: %d rate: %d", __FILE__, __LINE__, *rate);
	return -1;
}

static int ohos_write_set_nchannels(MSFilter *obj, void *data) {
	int *n = (int *)data;
	OHOSAudioWriteData *ad = (OHOSAudioWriteData *)obj->data;
	ad->nchannels = *n;
	ad->audio_context->nchannels = *n;
	ms_message("%s: %d nchannels: %d", __FILE__, __LINE__, ad->nchannels);
	return 0;
}

static int ohos_write_get_nchannels(MSFilter *obj, void *data) {
	int *n = (int *)data;
	OHOSAudioWriteData *ad = static_cast<OHOSAudioWriteData*>(obj->data);
	*n = ad->nchannels;
	*n = ad->audio_context->nchannels;
	ms_message("%s: %d nchannels: %d", __FILE__, __LINE__, ad->nchannels);
	return 0;
}

static int dec_have_plc(BCTBX_UNUSED(MSFilter *f), void *arg) {
	*((int *)arg) = 0;
	return 0;
}

static MSFilterMethod dec_methods[] = {{MS_FILTER_SET_SAMPLE_RATE, set_sample_write_rate},
                                       {MS_FILTER_GET_SAMPLE_RATE, get_sample_write_rate},
                                       {MS_FILTER_SET_NCHANNELS, ohos_write_set_nchannels},
                                       {MS_FILTER_GET_NCHANNELS, ohos_write_get_nchannels},
                                       {MS_DECODER_HAVE_PLC, dec_have_plc},
                                       {0, NULL}};

// MS_FILTER_DECODER_RENDERER
MSFilterDesc ms_ohos_audio_dec_desc = {.id = MS_OHOS_AUDIO_DEC,
                                       .name = "OHOSAudioDecode",
                                       .text = N_("ohos audio decoder"),
                                       .category = MS_FILTER_OTHER,
                                       .enc_fmt = "pcmu",
                                       .ninputs = 1,
                                       .noutputs = 0,
                                       .init = ohos_dec_init,
                                       .preprocess = ohos_dec_preprocess,
                                       .process = ohos_dec_process,
                                       .postprocess = ohos_dec_postprocess,
                                       .uninit = ohos_dec_uninit,
                                       .methods = dec_methods};

MS_FILTER_DESC_EXPORT(ms_ohos_audio_dec_desc)

#include "mediastreamer2/mssndcard.h"

// 虚拟设备打开 reader（采集设备）
MSFilter *ohos_create_reader(MSSndCard *card) {
	ms_message("OHOS create_reader");
	MSFilter *f = ms_factory_create_filter_from_desc(ms_snd_card_get_factory(card), &ms_ohos_audio_enc_desc);
	AlawEncData *ictx = static_cast<AlawEncData*>(f->data);
	ictx->soundCard = ms_snd_card_ref(card);
	ictx->sample_rate = card->preferred_sample_rate;
	ictx->deviceId = ictx->soundCard->internal_id;
	ictx->audio_context = (AudioContext*)card->data;
	ms_message("GetDevices ohos_create_reader,rate:%d",card->preferred_sample_rate);
	return f;
}

// 虚拟设备打开 writer（播放设备）
static MSFilter *ohos_create_writer(MSSndCard *card) {
	ms_message("OHOS create_writer");
	MSFilter *f = ms_factory_create_filter_from_desc(ms_snd_card_get_factory(card), &ms_ohos_audio_dec_desc);
	OHOSAudioWriteData *octx = static_cast<OHOSAudioWriteData*>(f->data);
	octx->soundCard = ms_snd_card_ref(card);
	octx->rate = card->preferred_sample_rate;
	octx->nchannels = ((AudioContext*)card->data)->nchannels;
	octx->setContext((AudioContext*)card->data);
	ms_message("GetDevices ohos_create_writer--->,nchannels:%d",octx->nchannels);
	return f;
}

// 初始化和反初始化（可选）
static void ohos_card_init(MSSndCard *card) {
	AudioContext* context = new AudioContext();
	card->data = context;
}
static void ohos_card_uninit(MSSndCard *card) {
	AudioContext *ctx = (AudioContext*)card->data;
	ms_message("Deletion of AAudio context [%p]", ctx);
	delete ctx;
}

static void ohos_snd_card_detect(MSSndCardManager *m);

// 定义 MSSndCardDesc（新版结构）
MSSndCardDesc ohos_snd_card_desc = {.driver_type = "OHOSVirtualAudio",
                                    .detect = ohos_snd_card_detect,
                                    .init = ohos_card_init,
                                    .set_level = NULL,
                                    .get_level = NULL,
                                    .set_capture = NULL,
                                    .set_control = NULL,
                                    .get_control = NULL,
                                    .create_reader = ohos_create_reader,
                                    .create_writer = ohos_create_writer,
                                    .uninit = ohos_card_uninit,
                                    .duplicate = NULL,
                                    .unload = NULL,
                                    .usage_hint = NULL,
                                    .audio_session_activated = NULL,
                                    .callkit_enabled = NULL,
                                    .audio_route_changed = NULL,
                                    .configure = NULL,
                                    .reload_requested = NULL};


static void snd_card_device_create(AudioDeviceInfo deviceInfo, const char *deviceName, 
											MSSndCardDeviceType type, 
											SoundDeviceDescription *deviceDescription, 
											MSSndCardManager *m) {
	if (
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_EARPIECE) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_SPEAKER) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_MICROPHONE) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADSET) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADPHONES) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEARING_AID) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_GENERIC_USB)
	) {

		MSSndCard *card = ms_snd_card_new(&ohos_snd_card_desc);
		card = ms_snd_card_ref(card);

		ms_snd_card_set_name(card, deviceName);
		AudioContext *card_data = (AudioContext*)card->data;
		card->internal_id = deviceInfo.id;
		card->device_type = type;
		card->device_description = deviceDescription;
		card->preferred_sample_rate = deviceInfo.supportedClockRates;
		card_data->nchannels = deviceInfo.supportedChannelCounts; 
		unsigned int cap = MS_SND_CARD_CAP_DISABLED;
		if (deviceInfo.inputCount>0)
		{
			cap |= MS_SND_CARD_CAP_CAPTURE;
		}
		if (deviceInfo.outputCount>0)
		{
			cap |= MS_SND_CARD_CAP_PLAYBACK;
		}
		card->capabilities = cap;
		if (deviceDescription->flags & DEVICE_HAS_CRAPPY_AAUDIO) {
			ms_warning("Device has been dynamically blacklisted using DEVICE_HAS_CRAPPY_AAUDIO flag");
			ms_snd_card_unref(card);
			return;
		}
		bool isBottom = false;
		if ((card->capabilities & MS_SND_CARD_CAP_CAPTURE) == MS_SND_CARD_CAP_CAPTURE) {
			const char *address = deviceInfo.address.c_str();
			if (address != NULL && strcmp(address, "bottom") == 0) {
				ms_message("Microphone device has [%s] address", address);
				isBottom = true;
			} else {
				ms_message("Microphone device have [%s] address, assuming not bottom (back)", address);
			}
			if (deviceDescription->flags & DEVICE_HAS_BUILTIN_AEC) {
				card->capabilities |= MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER;
				card_data->builtin_aec = true;
			}
		}
		card->latency = deviceDescription->delay;
		if (!ms_snd_card_is_card_duplicate(m, card, TRUE)) {
			ms_snd_card_manager_prepend_card(m, card);
			ms_message("Added card with ID [%s], name [%s], device ID [%0d], type [%s] and capabilities [%0d]", card->id, card->name, card->internal_id, ms_snd_card_device_type_to_string(card->device_type), card->capabilities);
		} else {
			if (ms_snd_card_get_device_type(card) == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_MICROPHONE) {
				MSSndCard *duplicate = ms_snd_card_get_card_duplicate(m, card, TRUE);
				if (duplicate) {
					if (isBottom) {
						ms_warning("[AAudio] Back microphone already added with device ID [%0d], removing it and adding bottom microphone ID [%0d] instead with back ID as alternative", duplicate->internal_id, card->internal_id);
						card->alternative_id = duplicate->internal_id;
						ms_snd_card_manager_prepend_card(m, card);
						ms_snd_card_manager_remove_card(m, duplicate);
					} else {
						ms_message("[AAudio] Bottom microphone already added with device ID [%0d], storing back microphone ID [%0d] as alternative in it", duplicate->internal_id, card->internal_id);
						duplicate->alternative_id = card->internal_id;
					}
					ms_snd_card_unref(duplicate);
				}
			} else {
				ms_message("[AAudio] Card with ID [%s], name [%s], device ID [%0d], type [%s] and capabilities [%0d] not added, considered as duplicate", card->id, card->name, card->internal_id, ms_snd_card_device_type_to_string(card->device_type), card->capabilities);
			}
			ms_snd_card_unref(card);	
		}
	} else {
		ms_message("[AAudio] SKipped device with type [%s]", ms_snd_card_device_type_to_string(type));
	}

}

static void ohos_snd_card_detect(MSSndCardManager *m) {
	SoundDeviceDescription *d = NULL;
	MSDevicesInfo *devices = NULL;

	devices = ms_factory_get_devices_info(m->factory);
	d = ms_devices_info_get_sound_device_description(devices);

	std::vector<AudioDeviceInfo> devicesArray = AudioDeviceManager::GetDevices();

	int dev_count = devicesArray.size();
	char *device_name = nullptr;
	char *a2dp_device_name = nullptr;
	for (int idx=0; idx < dev_count; idx++) {
		AudioDeviceInfo classDeviceInfo = devicesArray[idx];
		const char *deviceName  = classDeviceInfo.name.c_str();
		MSSndCardDeviceType type = classDeviceInfo.autoType;

		snd_card_device_create(classDeviceInfo,deviceName,type,d,m);

		if (device_name == nullptr &&
			(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_EARPIECE 
				|| type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_SPEAKER)) {
			device_name = ms_strdup(deviceName);
		} else if (a2dp_device_name == nullptr &&
			type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH_A2DP) {
			a2dp_device_name = ms_strdup(deviceName);
		}
	}
	if (device_name != nullptr && a2dp_device_name != nullptr) {
		const bctbx_list_t *cards = ms_snd_card_manager_get_list(m);
		bctbx_list_t *elem;
		for (elem = (bctbx_list_t *)cards; elem != NULL; elem = elem->next) {
			MSSndCard *card = (MSSndCard *)elem->data;
			if (card != nullptr && ms_snd_card_get_device_type(card) == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH && strcmp(ms_snd_card_get_name(card), device_name) == 0) {
				ms_warning("It seems bluetooth SCO device's name [%s] is the same as this device, updating it using A2DP device name [%s]", device_name, a2dp_device_name);
				ms_snd_card_set_name(card, a2dp_device_name);
			}
		}
	}
	if (device_name != nullptr) {
		ms_free(device_name);
	}
	if (a2dp_device_name != nullptr) {
		ms_free(a2dp_device_name);
	}
	// MSSndCard *card = ohos_snd_card_new(d);
	// ms_snd_card_set_manager(m, card);
	// ms_snd_card_manager_add_card(m, card);
}